#include "card_app.h"
#include "usb_mdwr.h"
#include "gdisp_lld_mdwr.h"
#include <stdio.h>

void ep2ReceiveHandler(uint8_t* pBufferPointer, uint8_t wBufferSize);
void ep4ReceiveHandler(uint8_t* pBufferPointer, uint8_t wBufferSize);
DataForEpInHandler ep1TransmitHandler(void);
DataForEpInHandler ep3TransmitHandler(void);

static void cardStartBitmap(CARD_TypeProtocol *card_type_protocol);
static void cardSequelBitmap(CARD_TypeProtocol *card_type_protocol);
static void cardLedsState(CARD_TypeProtocol *card_type_protocol);
static void cardJpegData(CARD_TypeProtocol *card_type_protocol);

const uint8_t BufferTxEp1[] = "Hello from the function ep1 TransmitHandler(void).";
const uint8_t BufferTxEp3[] = "Hello from the function ep3 TransmitHandler(void).";

void ep2ReceiveHandler(uint8_t* pBufferPointer, uint8_t wBufferSize)
{
	CARD_TypeProtocol *card_type_protocol = (void *)pBufferPointer;

	if(card_type_protocol->addr == CARD_ADDR)
	{
		switch(card_type_protocol->type)
		{
			case CARD_START_BITMAP_TYPE_DATA:
						cardStartBitmap(card_type_protocol);
						break;
			case CARD_SEQUEL_BITMAP_TYPE_DATA:
						cardSequelBitmap(card_type_protocol);
						break;
			case CARD_LEDS_STATE_TYPE_DATA:
						cardLedsState(card_type_protocol);
						break;
			case CARD_JPEG_TYPE_DATA:
						cardJpegData(card_type_protocol);
						break;
			default: printf("Bad type protocol!\r");
		}
	}
}

static void cardStartBitmap(CARD_TypeProtocol *card_type_protocol)
{
	CARD_StartBitmapTypeData *card_start_bitmap = (void *)(card_type_protocol->data);

	printf("card_start_bitmap->start_x = %d\r", card_start_bitmap->start_x);
	printf("card_start_bitmap->start_y = %d\r", card_start_bitmap->start_y);
	printf("card_start_bitmap->end_x = %d\r", card_start_bitmap->end_x);
	printf("card_start_bitmap->end_y = %d\r", card_start_bitmap->end_y);

	lld_lcdSetViewPort(card_start_bitmap->start_x, card_start_bitmap->start_y,\
										card_start_bitmap->end_x, card_start_bitmap->end_y);
	lld_lcdWriteStreamStart();
}

static void cardSequelBitmap(CARD_TypeProtocol *card_type_protocol)
{
	CARD_SequelBitmapTypeData *card_sequel_bitmap = (void *)(card_type_protocol->data);

	lld_lcdWriteStream(card_sequel_bitmap->data, card_sequel_bitmap->data_count);
}

static void cardLedsState(CARD_TypeProtocol *card_type_protocol)
{
	CARD_LedsState *card_leds_state = (void *)(card_type_protocol->data);

	if(card_leds_state->num_of_leds == CARD_LED_NUM)
	{
		if(card_leds_state->state)
		{
			GPIO_ResetBits(GPIOA, GPIO_Pin_2);
			printf("Led On!\r");
		}
		else
		{
			GPIO_SetBits(GPIOA, GPIO_Pin_2);
			printf("Led Off!\r");
		}
	}
}

void cardJpegData(CARD_TypeProtocol *card_type_protocol)
{
	CARD_JpegTypeData *card_jpeg_data = (void *)(card_type_protocol->data);
	/* Appended later! */
}

void ep4ReceiveHandler(uint8_t* pBufferPointer, uint8_t wBufferSize)
{
	printf(" ep4ReceiveHandler: data = %d, size = %d.\r", pBufferPointer[0], wBufferSize);

	if(pBufferPointer[0]%2 == 0x00)
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);
	}
	else
	{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);
	}
}

DataForEpInHandler ep1TransmitHandler(void)
{
	DataForEpInHandler data;

	data.pBufferPointer = (uint8_t *)BufferTxEp1;
	data.wBufferSize = sizeof(BufferTxEp1);

	printf(" ep1TransmitHandler.\r");

	return data;
}

DataForEpInHandler ep3TransmitHandler(void)
{
	DataForEpInHandler data;

	data.pBufferPointer = (uint8_t *)BufferTxEp3;
	data.wBufferSize = sizeof(BufferTxEp3);

	printf(" ep3TransmitHandler.\r");

	return data;
}

void USB_APP_Init(void)
{
	ErrorStatus status;

	/* Initialization callback functions. */
	USB_EpOutIrqHandlers[MDWR_NUM_OUT_EP_0] = ep2ReceiveHandler;
	USB_EpOutIrqHandlers[MDWR_NUM_OUT_EP_1] = ep4ReceiveHandler;

	USB_EpInIrqHandlers[MDWR_NUM_IN_EP_0] = ep1TransmitHandler;
	USB_EpInIrqHandlers[MDWR_NUM_IN_EP_1] = ep3TransmitHandler;

	status = USB_MDWR_Init();
	if(status == SUCCESS)
	{
		printf(" USB configured and running.\r");

	}
	/* Enable the transmit of data on MDWR_NUM_IN_EP_0 and MDWR_NUM_IN_EP_1 */
	USB_MDWR_SetEp0TxValid();
	USB_MDWR_SetEp1TxValid();
}
